#include "file_cmd.h"
#include "fatfs.h"
#include "stdio.h"
#include "string.h"
#include "system.h"
#include "FreeRTOS_CLI.h"
#define LOG_TAG "file_cmd"

static uint8_t find_parameter_num(const char *pcCommandString);
static uint8_t find_parameters(const char *pcCommandString, char **parameterArr);


static BaseType_t cd_command(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString);
static BaseType_t cat_command(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString);
static BaseType_t ls_command(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString);
static BaseType_t mkdir_command(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString);
static BaseType_t rm_command(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString);
static BaseType_t touch_command(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString);


/**
 * @defgroup FreeRTOS CLI命令组件 
 * {
 */
static const CLI_Command_Definition_t file_command[] = {
    {
    .pcCommand = "cd",\
    .pcHelpString = "cd:\t\tcd into dir\r\n", \
    .pxCommandInterpreter = cd_command, \
    .cExpectedNumberOfParameters = -1}, 
    {
    .pcCommand = "cat",\
    .pcHelpString = "cat:\t\topen file\r\n", \
    .pxCommandInterpreter = cat_command, \
    .cExpectedNumberOfParameters = -1},
    {
    .pcCommand = "ls",\
    .pcHelpString = "ls:\t\tfiles list in dir\r\n", \
    .pxCommandInterpreter = ls_command, \
    .cExpectedNumberOfParameters = 0},
    {
    .pcCommand = "mkdir",\
    .pcHelpString = "mkdir:\t\tcreat a floder\r\n", \
    .pxCommandInterpreter = mkdir_command, \
    .cExpectedNumberOfParameters = -1},
    {
        .pcCommand = "rm",\
        .pcHelpString = "-r:\t\tdelete dir\r\n", \
        .pxCommandInterpreter = rm_command, \
        .cExpectedNumberOfParameters = -1},
    {
        .pcCommand = "touch",\
        .pcHelpString = "rm:\t\tcreat a file\r\n", \
        .pxCommandInterpreter = touch_command, \
        .cExpectedNumberOfParameters = -1},
};
/**
 * }
 */





#define MAX_PATH_LEN 100
#define MAX_FILE_NAME_LEN 20
static DIR dir;
static char now_floder_path[MAX_PATH_LEN] = "0:/";          //当前目录路径 用于打开目录
static char now_file_path[MAX_PATH_LEN + MAX_FILE_NAME_LEN];//当前文件路径 用于打开文件

/**
 * @brief 文件命令初始化
 *        在任务调度开始之前使用
 * @param  
 */
void file_cmd_init(void)
{
    memcpy(now_floder_path, USERPath, strlen(USERPath));
    for (uint8_t i = 0; i < sizeof(file_command)/sizeof(file_command[0]); i++)
    {
        FreeRTOS_CLIRegisterCommand( &file_command[i] );	
    }
}




/**
 * @brief 创建文件夹路径
 * @param path 路径
 */
static void create_folder_path(char *path)
{
    int path_len = strlen(now_floder_path);
    if (strstr(path, ".."))//返回上一级目录
    {
        int last_path_index = 0;
        for (int i = 0; i < path_len; ++i)
        {
            if (now_floder_path[i] == '/')
            {
                last_path_index = i;
            }
        }
        if (last_path_index != 0)
        {
            memset(now_floder_path + last_path_index, 0, MAX_PATH_LEN - last_path_index);
        }
    }
    else if (strstr(path, "0:"))//使用绝对路径
    {
        memset(now_floder_path, 0, MAX_PATH_LEN);
        strcat(now_floder_path, path);
    }
    else//使用相对路径
    {
        if (now_floder_path[path_len - 1] == '/')
        {
            strcat(now_floder_path, path);
        }
        else
        {
            now_floder_path[path_len] = '/';
            strcat(now_floder_path, path);
        }
    }

}

/**
 * @brief 创建文件路径
 * @param file_name 文件名
 */
static void create_file_path(char *file_name)
{
    memset(now_file_path, 0, MAX_PATH_LEN + MAX_FILE_NAME_LEN);
    strcat(now_file_path, now_floder_path);
    int path_len = strlen(now_file_path);
    if (now_file_path[path_len - 1] != '/')
    {
        now_file_path[strlen(now_floder_path)] = '/';
    }
    strcat(now_file_path, file_name);
}



static BaseType_t cd_command(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString)
{
( void ) pcCommandString;
( void ) xWriteBufferLen;
configASSERT( pcWriteBuffer );
pcWriteBuffer[0] = '\0'; 
char **parameterArray = (char **)pvPortMalloc(sizeof(char *) * find_parameter_num(pcCommandString));
if (parameterArray == NULL)
{
    log_e("内存分配失败 按下Enter重试 \r\n");
    vPortFree(parameterArray);
    return pdFALSE;
}
if (find_parameters(pcCommandString, parameterArray) == 0)\
{
    log_w("没有找到参数, 请检查command格式 \r\n");
    vPortFree(parameterArray);
    return pdFALSE;
}
    /******* USER CODE BEGIN *******/
    FRESULT res;
    if (parameterArray[0] == "..")
    {
        f_closedir(&dir);
        create_folder_path(parameterArray[0]);
        res = f_opendir(&dir, now_floder_path);
        if (res == FR_OK)
        {
            log_v("当前目录: %s \r\n", now_floder_path);
        }
        else
        {
            log_e("打开目录失败 ");
            create_folder_path("..");
        }
    }
    else
    {
        f_closedir(&dir);
        create_folder_path(parameterArray[0]);
        res = f_opendir(&dir, now_floder_path);
        if (res == FR_OK)
        {
            log_v("当前目录: %s \r\n", now_floder_path);
        }
        else
        {
            log_e("打开目录失败 ");
            create_folder_path("..");
        }
    }
    /*******  USER CODE END *******/

vPortFree(parameterArray);
return pdFALSE;
}


static BaseType_t cat_command(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString)
{
( void ) pcCommandString;
( void ) xWriteBufferLen;
configASSERT( pcWriteBuffer );
memset(pcWriteBuffer, 0, xWriteBufferLen);  
char **parameterArray = (char **)pvPortMalloc(sizeof(char *) * find_parameter_num(pcCommandString));
if (parameterArray == NULL)
{
    log_e("内存分配失败 按下Enter重试 \r\n");
    vPortFree(parameterArray);
    return pdFALSE;
}
if (find_parameters(pcCommandString, parameterArray) == 0)\
{
    log_w("没有找到参数, 请检查command格式 \r\n");
    vPortFree(parameterArray);
    return pdFALSE;
}
    /******* USER CODE BEGIN *******/
    file_cat_print(now_floder_path, parameterArray[0], pcWriteBuffer, xWriteBufferLen);
    /*******  USER CODE END *******/

vPortFree(parameterArray);
return pdFALSE;
}

static BaseType_t ls_command(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString)
{
( void ) pcCommandString;
( void ) xWriteBufferLen;
configASSERT( pcWriteBuffer );
pcWriteBuffer[0] = '\0';  

    /******* USER CODE BEGIN *******/
    file_dir_scan(now_floder_path, pcWriteBuffer, xWriteBufferLen);
    /*******  USER CODE END *******/

return pdFALSE;
}



static BaseType_t mkdir_command(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString)
{
( void ) pcCommandString;
( void ) xWriteBufferLen;
configASSERT( pcWriteBuffer );
memset(pcWriteBuffer, 0, xWriteBufferLen);  
char **parameterArray = (char **)pvPortMalloc(sizeof(char *) * find_parameter_num(pcCommandString));
if (parameterArray == NULL)
{
    log_e("内存分配失败 按下Enter重试 \r\n");
    vPortFree(parameterArray);
    return pdFALSE;
}
if (find_parameters(pcCommandString, parameterArray) == 0)\
{
    log_w("没有找到参数, 请检查command格式 \r\n");
    vPortFree(parameterArray);
    return pdFALSE;
}
    /******* USER CODE BEGIN *******/
    FRESULT res;
    create_folder_path(parameterArray[0]);
    f_closedir(&dir);
    res = f_opendir(&dir, now_floder_path);
    if (res == FR_OK)
    {
        log_w("目录已存在 已经打开 ");
    }
    else
    {
        res = f_mkdir(now_floder_path);
        if (res == FR_OK)
        {
            log_i("创建目录成功 ");
        }
        else
        {
            log_e("创建目录失败 ");
        }
    }
    create_folder_path("..");
    /*******  USER CODE END *******/

vPortFree(parameterArray);
return pdFALSE;
}


static BaseType_t rm_command(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString)
{
( void ) pcCommandString;
( void ) xWriteBufferLen;
configASSERT( pcWriteBuffer );
memset(pcWriteBuffer, 0, xWriteBufferLen);  
uint8_t parameterNum = find_parameter_num(pcCommandString);
char **parameterArray = (char **)pvPortMalloc(sizeof(char *) * parameterNum);
if (parameterArray == NULL)
{
    log_e("内存分配失败 按下Enter重试 \r\n");
    vPortFree(parameterArray);
    return pdFALSE;
}
if (find_parameters(pcCommandString, parameterArray) == 0)\
{
    log_w("没有找到参数, 请检查command格式 \r\n");
    vPortFree(parameterArray);
    return pdFALSE;
}
    /******* USER CODE BEGIN *******/
    if (parameterNum >= 2)
    {
        FRESULT res;
        if (strstr(parameterArray[0], "r"))
        {
            create_folder_path(parameterArray[1]);
            res = file_delete_recursive(now_floder_path);
            if (res == FR_OK)
            {
                log_i("删除成功");
                
            }
            else
            {
                log_e("删除失败 (%d)", res);
            }
            create_folder_path("..");
        }
    }
    /*******  USER CODE END *******/

vPortFree(parameterArray);
return pdFALSE;
}


static BaseType_t touch_command(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString)
{
( void ) pcCommandString;
( void ) xWriteBufferLen;
configASSERT( pcWriteBuffer );
memset(pcWriteBuffer, 0, xWriteBufferLen);  
char **parameterArray = (char **)pvPortMalloc(sizeof(char *) * find_parameter_num(pcCommandString));
if (parameterArray == NULL)
{
    log_e("内存分配失败 按下Enter重试 \r\n");
    vPortFree(parameterArray);
    return pdFALSE;
}
if (find_parameters(pcCommandString, parameterArray) == 0)\
{
    log_w("没有找到参数, 请检查command格式 \r\n");
    vPortFree(parameterArray);
    return pdFALSE;
}

    /******* USER CODE BEGIN *******/
    file_create_file(now_floder_path, parameterArray[0], NULL, 0);
    /*******  USER CODE END *******/

vPortFree(parameterArray);
return pdFALSE;
}




/***********************************************内部调用***************************************************************************** */

/**
 * @brief 提取参数放入字符串数组
 * @param pcCommandString 整个参数字符串
 * @param parameterArr 字符串数组，存放提取出的参数
 * @return 找到的参数个数
 */
static uint8_t find_parameters(const char *pcCommandString, char **parameterArr)
{
    uint8_t len = strlen(pcCommandString);
    uint8_t found_num = 0;
    uint8_t parameter_num = 0;//总参数数量
    for (uint8_t i = 0; i < len - 1; i++)//寻找参数总数量 
    {
        if (pcCommandString[i] == ' ' && pcCommandString[i + 1] != ' ')
        {
            parameter_num++;
        }
    }
    if (parameter_num == 0)
    {
        return 0;
    }
    
    uint8_t *index = (uint8_t*) pvPortMalloc(sizeof(uint8_t) * (parameter_num + 1));  // 增加一个元素用于最后一个参数
    if (index == NULL)
    {
        return 0;
    }

    // 找到参数位置
    for (uint8_t i = 0; i < len - 1; i++)
    {
        if (pcCommandString[i] == ' ' && pcCommandString[i + 1] != ' ')
        {
            index[found_num++] = i + 1;
            if (found_num == parameter_num)
                break;
        }
    }

    // 提取处理参数
    for (uint8_t i = 0; i < found_num; i++)
    {
        uint8_t start = index[i];
        uint8_t end = 0;
        if (i % 2 == 0)
            end = (i + 1 < found_num) ? index[i + 1] - 1: len;  // 确保最后一个参数处理正确
        else
            end = (i + 1 < found_num) ? index[i + 1] - 2: len;  // 确保最后一个参数处理正确
        uint8_t param_len = end - start;

        parameterArr[i] = (char *)pvPortMalloc(param_len + 1);  // 分配内存
        if (parameterArr[i] == NULL)//错误处理
        {
            for (uint8_t j = 0; j < i; j++)
            {
                vPortFree(parameterArr[j]);
            }
            vPortFree(index);
            return 0;
        }
        memcpy(parameterArr[i], pcCommandString + start, param_len);
        parameterArr[i][param_len] = '\0';  // 添加字符串结束符 避免乱码
    }

    vPortFree(index);
    return found_num;
}

/**
 * @brief 寻找参数总数量
 * @param pcCommandString 命令字符串
 * @return 参数数量
 */
static uint8_t find_parameter_num(const char *pcCommandString)
{
    uint8_t len = strlen(pcCommandString);
    uint8_t parameter_num = 0;
    for (uint8_t i = 0; i < len - 1; i++)
    {
        if (pcCommandString[i] == ' ' && pcCommandString[i + 1] != ' ')
        {
            parameter_num++;
        }
    }
    return parameter_num;
}
